
 #include "bsp_shell.h"

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

// ==== 配置参数 ====
#define CMD_MAX_LEN        64
#define HISTORY_MAX_COUNT  8
#define MAX_CMD_COUNT      16
#define MAX_ARGC           8   // 最大参数个数（含命令名）
#define PROMPT             ">> "

// ==== 历史命令 & 行编辑 ====
typedef struct {
    char buffer[HISTORY_MAX_COUNT][CMD_MAX_LEN];
    uint8_t head;   // 指向下一个写入位置
    uint8_t count;  // 当前有效命令数（<= HISTORY_MAX_COUNT）
} HistoryBuffer;

typedef struct {
    char buf[CMD_MAX_LEN];
    uint8_t len;
    uint8_t cursor;
} LineBuffer;

static HistoryBuffer history = {0};
static LineBuffer line = {0};

// 历史浏览状态：-1 = 未浏览；0 ~ (count-1) = 逻辑索引（0=最旧，count-1=最新）
static int8_t history_view_index = -1;

// ==== 底层 I/O ====
int getch(void)
{
    char ch = shell_byte_read();
    return ch;
}

void putch(char ch) {
    HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
}

void str_puts(const char *s) {
    while (*s) putch(*s++);
}

void backspace(void) {
    putch('\b');
    putch(' ');
    putch('\b');
}

// ==== 命令表 ====
typedef struct {
    cmd_handler_t handler;
    const char *name;
} shell_cmd_t;

static shell_cmd_t cmd_table[MAX_CMD_COUNT] = {0};
static uint8_t cmd_count = 0;

void shell_register(cmd_handler_t handler, const char *name)
{
    if (!handler || !name) return;

    for (int i = 0; i < cmd_count; i++) {
        if (strcmp(cmd_table[i].name, name) == 0) {
            printf("Warning: Command '%s' already registered. Ignoring.\r\n", name);
            return;
        }
    }

    if (cmd_count >= MAX_CMD_COUNT) {
        return;
    }

    cmd_table[cmd_count].handler = handler;
    cmd_table[cmd_count].name = name;
    cmd_count++;
}

cmd_handler_t shell_find_cmd(const char *cmd) {
    for (int i = 0; i < cmd_count; i++) {
        if (strcmp(cmd_table[i].name, cmd) == 0) {
            return cmd_table[i].handler;
        }
    }
    return NULL;
}

// ==== 行编辑 ====
void line_clear(void) {
    memset(&line, 0, sizeof(LineBuffer));
}

void line_clear_display(void) {
    for (uint8_t i = 0; i < line.len; i++) {
        backspace();
    }
}

void line_display(const char *str) {
    line_clear_display();
    line_clear();
    if (str) {
        uint8_t len = strlen(str);
        if (len >= CMD_MAX_LEN) len = CMD_MAX_LEN - 1;
        strncpy(line.buf, str, len);
        line.len = len;
        line.cursor = len;
        str_puts(str);
    }
}

void line_insert_char(char c) {
    if (line.len >= CMD_MAX_LEN - 1) return;
    for (int i = line.len; i > line.cursor; i--) {
        line.buf[i] = line.buf[i-1];
    }
    line.buf[line.cursor] = c;
    line.len++;
    line.cursor++;
    putch(c);
    for (int i = line.cursor; i < line.len; i++) {
        putch(line.buf[i]);
    }
    for (int i = line.cursor; i < line.len; i++) {
        putch('\b');
    }
}

void line_delete_char(void) {
    if (line.cursor == 0) return;
    line.cursor--;
    line.len--;
    for (int i = line.cursor; i < line.len; i++) {
        line.buf[i] = line.buf[i+1];
    }
    line.buf[line.len] = '\0';
    backspace();
    for (int i = line.cursor; i < line.len; i++) {
        putch(line.buf[i]);
    }
    putch(' ');
    backspace();
    for (int i = line.cursor; i < line.len; i++) {
        putch('\b');
    }
}

void line_move_left(void) {
    if (line.cursor > 0) {
        line.cursor--;
        putch('\b');
    }
}

void line_move_right(void) {
    if (line.cursor < line.len) {
        putch(line.buf[line.cursor]);
        line.cursor++;
    }
}

// ==== Tab 补全 ====
void tab_complete(LineBuffer *line) {
    if (line->len == 0) return;

    char input[CMD_MAX_LEN];
    strncpy(input, line->buf, line->len);
    input[line->len] = '\0';

    shell_cmd_t *matches[MAX_CMD_COUNT];
    uint8_t match_count = 0;

    for (int i = 0; i < cmd_count; i++) {
        if (strncmp(cmd_table[i].name, input, line->len) == 0) {
            matches[match_count++] = &cmd_table[i];
        }
    }

    if (match_count == 0) {
        putch('\a');
        return;
    }

    if (match_count == 1) {
        const char *cmd = matches[0]->name;
        uint8_t cmd_len = strlen(cmd);
        line_clear_display();
        line_clear();
        for (uint8_t i = 0; i < cmd_len; i++) {
            line_insert_char(cmd[i]);
        }
    } else {
        putch('\r');
        putch('\n');
        for (uint8_t i = 0; i < match_count; i++) {
            str_puts(matches[i]->name);
            putch(' ');
        }
        putch('\r');
        putch('\n');
        str_puts(PROMPT);
        str_puts(line->buf);
    }
}

// ==== 历史命令管理（关键修复部分）====
static uint8_t logical_to_physical(int8_t logic_idx) {
    if (logic_idx < 0 || logic_idx >= (int8_t)history.count) {
        return 0; // should not happen
    }
    int idx = (int)history.head - (int)history.count + (int)logic_idx;
    if (idx < 0) idx += HISTORY_MAX_COUNT;
    return (uint8_t)(idx % HISTORY_MAX_COUNT);
}

void history_add(const char *cmd) {
    if (strlen(cmd) == 0) return;
    strncpy(history.buffer[history.head], cmd, CMD_MAX_LEN - 1);
    history.buffer[history.head][CMD_MAX_LEN - 1] = '\0';
    history.head = (history.head + 1) % HISTORY_MAX_COUNT;
    if (history.count < HISTORY_MAX_COUNT) {
        history.count++;
    }
}

const char* history_prev(void) {
    if (history.count == 0) return NULL;

    if (history_view_index == -1) {
        // 首次按上：定位到最新命令（逻辑索引 = count - 1）
        history_view_index = history.count - 1;
    } else if (history_view_index > 0) {
        history_view_index--;
    }
    // 如果已在最旧（view_index == 0），保持不变

    uint8_t phys = logical_to_physical(history_view_index);
    return history.buffer[phys];
}

const char* history_next(void) {
    if (history.count == 0) return NULL;

    if (history_view_index == -1) {
        return NULL; // 未在浏览模式
    }

    if (history_view_index < (int8_t)(history.count - 1)) {
        history_view_index++;
        uint8_t phys = logical_to_physical(history_view_index);
        return history.buffer[phys];
    } else {
        // 回到新行
        history_view_index = -1;
        return ""; // 空字符串表示清空输入行
    }
}

void history_reset_cursor(void) {
    history_view_index = -1;
}

// ==== 参数解析 ====
static int parse_args(char *cmdline, char *argv[], int max_args) {
    int argc = 0;
    char *p = cmdline;
    int in_quote = 0;

    while (*p && argc < max_args - 1) {
        while (*p == ' ') p++;
        if (*p == '\0') break;

        argv[argc++] = p;

        while (*p && (in_quote || *p != ' ')) {
            if (*p == '"' || *p == '\'') {
                if (!in_quote) {
                    in_quote = *p;
                    argv[argc-1]++; // skip opening quote
                } else if (*p == in_quote) {
                    *p = '\0';
                    in_quote = 0;
                    break;
                }
            }
            p++;
        }

        if (*p == ' ' && !in_quote) {
            *p = '\0';
            p++;
        }
    }

    argv[argc] = NULL;
    return argc;
}

// ==== 内置命令 ====
int cmd_help(int argc, char **argv) {
    str_puts("Tiny Shell Help:\r\n");
    str_puts("Registered commands:\r\n");
    for (int i = 0; i < cmd_count; i++) {
        str_puts("  ");
        str_puts(cmd_table[i].name);
        putch('\r');
        putch('\n');
    }
    return 0;
}

int cmd_clear(int argc, char **argv) {
    str_puts("\033[2J\033[H");
    return 0;
}

int cmd_exit(int argc, char **argv) {
    str_puts("Bye!\r\n");
    return -1;
}

void shell_init_commands(void) {
    shell_register(cmd_help, "help");
    shell_register(cmd_clear, "clear");
    shell_register(cmd_exit, "exit");
}

// ==== 命令执行 ====
void shell_execute(const char *cmd_str) {
    if (strlen(cmd_str) == 0) return;

    static char cmdline_copy[CMD_MAX_LEN];
    static char *argv[MAX_ARGC];

    strncpy(cmdline_copy, cmd_str, CMD_MAX_LEN - 1);
    cmdline_copy[CMD_MAX_LEN - 1] = '\0';

    int argc = parse_args(cmdline_copy, argv, MAX_ARGC);
    if (argc == 0) return;

    cmd_handler_t handler = shell_find_cmd(argv[0]);
    if (handler) {
        int ret = handler(argc, argv);
        if (ret == -1) {
            str_puts("Shell exiting...\r\n");
            while(1);
        }
    } else {
        str_puts("Unknown command: ");
        str_puts(argv[0]);
        putch('\r');
        putch('\n');
    }
}

// ==== Shell 主循环接口 ====
void shell_init(void)
{
    shell_init_commands();

    str_puts("\r\n");
    str_puts("Welcome to Tiny Shell v1.4 (Fixed History Navigation)\r\n");
    str_puts(PROMPT);
    
    shell_lwrb_init();
    user_shell_init();
}

void shell_fun(int c)
{
    switch (c) {
        case '\r':
        case '\n':
            putch('\r');
            putch('\n');
            if (line.len > 0) {
                line.buf[line.len] = '\0';
                history_add(line.buf);
                shell_execute(line.buf);
            }
            line_clear();
            str_puts(PROMPT);
            history_reset_cursor(); // 重置历史浏览状态
            break;

        case 127:
        case '\b':
            if (line.cursor > 0) {
                line_delete_char();
            }
            break;

        case 0x03: // Ctrl+C
            line_clear_display();
            line_clear();
            str_puts(PROMPT);
            history_reset_cursor();
            break;

        case '\t':
            if (line.len) {
                tab_complete(&line);
            } else {
                cmd_help(0, NULL);
            }
            break;

        case 0x1B: // ESC
            c = getch();
            if (c == '[') {
                c = getch();
                switch (c) {
                    case 'A': // Up arrow
                        {
                            const char* cmd = history_prev();
                            if (cmd) line_display(cmd);
                        }
                        break;
                    case 'B': // Down arrow
                        {
                            const char* cmd = history_next();
                            if (cmd) {
                                line_display(cmd);
                            } else {
                                line_display("");
                            }
                        }
                        break;
                    case 'C': // Right arrow
                        line_move_right();
                        break;
                    case 'D': // Left arrow
                        line_move_left();
                        break;
                }
            }
            break;

        default:
            if (c >= 32 && c <= 126 && line.len < CMD_MAX_LEN - 1) {
                line_insert_char((char)c);
            }
            break;
    }
}


